Disclaimer: Notebooks translated to Spanish are distributed as an optional aid to assist in your learning and comprehension. We make no guarantees that the translations are completely accurate nor that the translated code blocks will run properly.
import pandas as pd
import numpy as np
import json
import plotly.express as px
from datetime import datetime as dt
import warnings
warnings.filterwarnings('ignore')
Contexto de Negocio. Usted es analista de inteligencia de negocios para un conglomerado de supermercados. Su empresa tiene tiendas en todo Estados Unidos. La compañía ha recopilado datos que consisten en información de pedidos por línea de todas sus tiendas. La compañía desea comparar los datos de ventas en diferentes meses y geografías y poner esta información a disposición de los miembros ejecutivos y accionistas clave. Si cada persona tiene acceso a un tablero interactivo, puede ofrecer una base para generar mejor diálogo y una excelente toma de decisiones.
Problema de Negocio. La compañía quiere que usted haga un tablero interactivo que los ejecutivos de la compañía puedan usar para visualizar las ventas y las ganancias en las ubicaciones de los supermercados durante varios períodos de tiempo. El tablero debe poder usarse a través de un navegador web como Chrome en la intranet de la compañía.
Contexto Analítico. En el caso actual, utilizaremos Dash by Plotly para desarrollar el tablero. Dash es una plataforma de Business Intelligence (BI) de código abierto que nos permite desarrollar paneles interactivos complicados utilizando solo Python. También nos permite conectarnos a varias fuentes de datos y es fácil de implementar como una aplicación web.
El caso está estructurado de la siguiente manera: (1) aprenderá sobre los componentes básicos de Dash; (2) hará un recorrido a través de los elementos básicos para hacer un tablero de instrumentos; y finalmente (3) haga un tablero que compare las ventas y las ganancias a lo largo del tiempo en varios estados.
Importemos los datos en un dataframe de pandas y echemos un vistazo a toda la información que tenemos:
df = pd.read_csv('App/Data/superstore.csv', parse_dates=['Order Date', 'Ship Date'])
df.head()
df.columns
La información del supermercado se encuentra a nivel de línea para cada producto comprado en diferentes ubicaciones. La lista completa de características disponibles está a continuación:
Antes de comenzar con el desarrollo de nuestro tablero, es importante determinar qué tipo de información y visualizaciones pueden ser útiles para nuestro cliente. ¿Cuál de las siguientes gráficas cree que es importante incluir en nuestro tablero? Seleccione todas las que correspondan.
I. Un diagrama de caja que muestra la distribución de las cantidades vendidas en cada venta a lo largo del tiempo.
II Un mapa de los Estados Unidos que destaca el valor de las ventas de sus productos en todos los estados.
III. Un diagrama de dispersión del valor frente a las ganancias de cada venta.
IV. Un diagrama de lineas que compara las ventas en todas las ciudades a lo largo del tiempo.
V. Un diagrama de lineas que compara las ventas entre estados seleccionados por el usuario a lo largo del tiempo.
Respuesta.
En este caso, utilizaremos Plotly Express para crear los gráficos que estarán en nuestro tablero. Una de las grandes ventajas de Plotly Express es su facilidad de uso y flexibilidad al crear gráficos interactivos. Por ejemplo, podemos crear un diagrama de dispersión de ventas (Sales) versus ganancias (Profit) de la siguiente manera:
px.scatter(df, x="Sales", y="Profit", color="Category")
Observe cómo es realmente fácil hacer zoom en ciertas regiones del gráfico (haga doble clic para ir a la vista estándar). También podemos ver que el texto flotante aparece cuando colocamos el cursor encima de un punto en el gráfico. Podemos agregar más información a los datos de desplazamiento de la siguiente manera:
px.scatter(df, x="Sales", y="Profit", color="Category", hover_data=['State','Sub-Category','Order ID','Product Name'])
Cree un diagrama lineal que muestre el historial de las ventas mensuales totales de la compañía en los estados de California, Nueva York y Texas. El gráfico debe tener tres líneas (una por estado). ¿Ve alguna tendencia en las ventas en estos estados?
Pista: Use el comando px.line para crear un diagrama de línea. Cree una nueva columna que extraiga el mes y el año de cada venta con el comando:
df['Order_Month'] = pd.to_datetime(df['Order Date'].map(lambda x: "{}-{}".format(x.year, x.month)))
Respuesta.
Un mapa coroplético es un tipo de mapa temático que se utiliza para visualizar datos estadísticos en regiones geográficas. Los mapas coropléticos generalmente se crean utilizando tres componentes básicos: un API de mapas (como Google Maps, Bing o Mapbox) para recuperar información actualizada del mapa y otras funcionalidades, un archivo GeoJSON que contiene coordenadas que delimitan las áreas (polígonos) de interés, y los datos reales que se imprimirán en el mapa.
En la carpeta Data, hemos agregado un archivo GeoJSON llamado us.json que contiene los datos geográficos de todos los estados de EE.UU. En este GeoJSON, cada estado tiene un identificador único correspondiente a su abreviatura: CA, NY,TX, y así sucesivamente. Como nuestro DataFrame contiene nombres completos, también hemos incluido un archivo JSON llamado states.json, que es simplemente un diccionario que indica los nombres completos de los estados y sus abreviaturas. Carguemos estos datos y creemos una nueva columna en nuestro DataFrame con las abreviaturas:
with open('App/Data/us.json') as geo:
geojson = json.loads(geo.read())
with open('App/Data/states.json') as f:
states_dict = json.loads(f.read())
df['State_abbr'] = df['State'].map(states_dict)
Plotly Express usa Mapbox para crear mapas coropléticos a través de la función px.choropleth_mapbox(también puede usar la función px.choropleth si tiene acceso a un mapa base). Creemos un mapa coroplético que muestre las ventas totales en todos los estados de los EE.UU.:
dff=df.groupby('State_abbr').sum().reset_index()
#Aquí podemos ver la sintaxis utilizada para la creación de mapas coropléticos:
px.choropleth_mapbox(dff, #Data
locations='State_abbr', #Columna que contiene los identificadores utilizados en el archivo GeoJSON
color='Sales', #Columna que da la intensidad del color de la región
geojson=geojson, #El archivo GeoJSON
zoom=3, #Zoom
mapbox_style="carto-positron", #Estilo Mapbox, para diferentes mapas necesita una cuenta Mapbox y un token
center={"lat": 37.0902, "lon": -95.7129}, #Centrar
color_continuous_scale="Viridis", #Esquema de color
opacity=0.5, #Opacidad del mapa
)
Cree un mapa coroplético que resalte el número de ventas de Teléfonos desde el 4 de febrero de 2015 hasta el 6 de octubre de 2016 para los estados de la región sur. ¿En qué estados se encuentran los 3 principales vendedores de teléfonos? ¿Cuáles fueron sus ganancias totales?
Pista: Para codificar las fechas use dt(YYYY,MM,DD).date().
Respuesta.
Volvamos ahora al problema de negocio en cuestión. Recuerde la solicitud original, que permitía a las partes interesadas ejecutivas visualizar las ventas y las ganancias en los supermercados durante varios períodos de tiempo. ¿Qué características debe tener el tablero para satisfacer esto?
Estado (State) (existe Código postal (Postal Code), pero hay tantos códigos postales que esto daría como resultado que los datos se rompan tanto que ya no sean fácilmente interpretables) . Por lo tanto, tiene sentido que el panel permita a los usuarios filtrar las ventas y las ganancias por estado.En este punto, es una buena idea tener un boceto en mente para nuestro tablero. Se pueden encontrar varios ejemplos en Dash App Gallery, que se pueden descargar y utilizar como inspiración para nuestro tablero de control. Aunque muchos de estos paneles parecen complicados, la mayoría de ellos no son difíciles de hacer.

En esencia, las aplicaciones Dash son aplicaciones web que consisten en componentes que usan Flask, ReactJS, Javascript y Plotly. Los autores de Dash se han asegurado de que no necesitemos interactuar con ninguno de estos componentes directamente a través de estos otros marcos, y en su lugar podemos interactuar con todos ellos utilizando solo Python.
Todas las aplicaciones Dash se componen de dos partes:
Diseño : Consiste en los componentes que usamos en nuestra aplicación (por ejemplo, selectores, diagramas, elementos HTML, div, etc.). El diseño se compone de componentes HTML (dash_html_components) y componentes centrales de Dash (dash_core_components). El diseño se establece utilizando el parámetro layout de la variableapp y es una lista de todos los componentes que se mostrarán en el navegador cuando lancemos nuestra aplicación Dash. Más específicamente:
Componentes HTML : nos permite usar etiquetas HTML comunes en Python como Div,H1, etc. Luego, Dash las convierte en HTML para el navegador. Además, también podemos pasar varias propiedades a los componentes HTML, como style , className e id . La lista completa de componentes HTML de Dash está disponible aquí: https://dash.plot.ly/dash-html-components.
Componentes principales del tablero : este grupo de componentes nos permite agregar gráficos, controles deslizantes, entradas, tablas, cargadores de archivos y más a nuestra aplicación usando solo código Python. Cada uno de estos componentes viene con su propio conjunto de parámetros que se pueden configurar para cambiar el aspecto, la sensación y la interactividad. La lista completa de componentes principales de Dash está disponible aquí: https://dash.plot.ly/dash-core-components.
Creemos nuestro primer tablero usando los siguientes pasos. En este ejercicio, usaremos Jupyter Lab; sin embargo, puede seguir pasos similares en su IDE de Python de preferencia (PyCharm, SublimeText, etc.). Solo asegúrese de que su IDE se esté ejecutando con el entorno virtual proporcionado para este caso y que tenga instaladas las librerías apropiadas.
En JupyterLab, busque el directorio de archivos donde está ejecutando este caso. Cree nuevas ventanas de Terminal y Texto (File->New->Terminal, Text File). En la ventana de Texto, pegue el siguiente código y guárdelo como Hello_Dash.py, luego ejecute el código en el terminal usandopython Hello_Dash.py. Finalmente, en su navegador vaya a http://127.0.0.1:8050/. ¿Que ve?
import dash
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_html_components as html
import plotly.express as px
import pandas as pd
import json
#Crea la app
app = dash.Dash(__name__)
#Crea el diseño
app.layout = html.Div([
html.H2("US Sales Map", id='title'), #Creates the title of the app
])
#Inicializa el servidor donde funcionará la aplicación
if __name__ == "__main__":
app.run_server(debug=True)
Respuesta.
Agregue un mapa coroplético de las ventas totales de la compañía al tablero. Para hacer esto, primero agregue el mapa coroplético creado antes del Ejercicio 3 en el código (también necesitará cargar los datos) y nombre la figura como Map_Fig. Finalmente, agregue un componente de gráfico de tablero al diseño agregando la línea:
dcc.Graph(figure=Map_Fig, id='main-figure')
Respuesta.
Finalmente, agreguemos una interactividad muy simple a nuestro tablero. Creemos un control deslizante que podamos usar para cambiar el mapa coroplético en el diagrama de dispersión creado justo antes del Ejercicio 2. Lo haremos en dos pasos. Comencemos agregando el diagrama de dispersión en el código y llamándolo Scatter_Fig. Luego, agregue un componente deslizante al diseño utilizando la sintaxis:
dcc.Slider(min=0,max=1,marks={0:'US Map', 1:'Scatter Plot'},value=0,id='fig-slider',)
La nueva aplicación debería verse así. Tenga en cuenta que mover el control deslizante no tiene ningún efecto en el tablero:

Dash nos permite construir interacciones entre sus componentes con el uso de funciones callback. Para crear una función de este tipo, simplemente necesitamos identificar los ID y las propiedades de los componentes con los que queremos interactuar y luego crear una función que codifique esta interacción.
Por ejemplo, queremos que la propiedad value del deslizador fig-slider modifique la propiedad figure de la figura main-figure. Además, queremos que value = 0 establezca figure = Fig_Map y value = 1 establezca figure = Scatter_Map. Podemos decirle a Dash que haga esto agregando el siguiente código a nuestra aplicación después del diseño:
@app.callback(
Output('main-figure','figure'),
[Input('fig-slider','value')])
def slider_interaction(slider_val):
if slider_val==0:
fig=Map_Fig
else:
fig=Scatter_Fig
return fig
Ejecute la aplicación una vez más y verifique que la función callback esté funcionando correctamente moviendo el control deslizante.
Nota: El app.callback es un decorador que agrega más funcionalidades a la función slider-interaction para que Dash pueda usarlo para actualizar la página web de acuerdo con los cambios en sus componentes.
La nueva aplicación debería verse así:


El código final de esta aplicación se muestra a continuación.
import dash
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
import pandas as pd
import json
##################################################################################################
#Cargar los datos y crear el mapa
##################################################################################################
df = pd.read_csv('Data/superstore.csv', parse_dates=['Order Date', 'Ship Date'])
with open('Data/us.json') as geo:
geojson = json.loads(geo.read())
with open('Data/states.json') as f:
states_dict = json.loads(f.read())
df['State_abbr'] = df['State'].map(states_dict)
#Crear el mapa:
dff=df.groupby('State_abbr').sum().reset_index()
Map_Fig=px.choropleth_mapbox(dff,
locations='State_abbr',
color='Sales',
geojson=geojson,
zoom=3,
mapbox_style="carto-positron",
center={"lat": 37.0902, "lon": -95.7129},
color_continuous_scale="Viridis",
opacity=0.5,
)
#Crear el diagrama de dispersión:
Scatter_Fig=px.scatter(df, x="Sales", y="Profit", color="Category", hover_data=['State','Sub-Category','Order ID','Product Name'])
################################################################################################
#Crear la app
app = dash.Dash(__name__)
#Crear el diseño
app.layout = html.Div([
html.H2("US Sales Map", id='title'), #Creates the title of the app
dcc.Graph(figure=Map_Fig, id='main-figure'),
dcc.Slider(min=0,max=1,marks={0:'US Map', 1:'Scatter Plot'},value=0, id='fig-slider')
])
@app.callback(
Output('main-figure','figure'),
[Input('fig-slider','value')])
def slider_interction(slider_val):
if slider_val==0:
fig=Map_Fig
else:
fig=Scatter_Fig
return fig
#Inicializar el servidor donde funcionará la aplicación.
if __name__ == "__main__":
app.run_server(debug=True)
¡Felicidades! ¡Ya ha aprendido las funcionalidades más importantes de Dash! Sin embargo, como puede ver en el Ejercicio 4, la aplicación resultante no se ve muy agradable a la vista y si seguimos agregando más funcionalidades y gráficos, nuestro código comenzará a verse desordenado muy pronto. Afortunadamente, podemos ordenar el código de nuestra aplicación con bastante facilidad dividiendo el diseño de nuestra aplicación en diferentes archivos. Por ejemplo, echemos un vistazo al árbol de archivos de la carpeta App proporcionada con el caso:
App
| app.py
| index.py
|
+---assets
| | ds4a-img.svg
| | ds4a_styles.css
| |
|
+---data
| | states.json
| | superstore.csv
| | us.json
| |
|
+---lib
| | sidebar.py
| | stats.py
| | styles.py
| | title.py
| | us_map.py
| | __init__.py
|
Hemos estructurado este sistema de archivos para que todas las diferentes partes del diseño de nuestra aplicación se encuentren en la carpeta lib, algunos estilos básicos y figuras se encuentran en la carpeta assets, y los datos utilizados en la aplicación se encuentran en la carpeta data. Las funciones callback y la definición del diseño se ubicarán en el archivo index.py, que es el que ejecutaremos desde el terminal. La forma en que funciona la estructura de archivos no es trivial, pero no nos preocupemos demasiado ahora (puede revisarla más adelante).
Los estilos se agregan a las páginas web HTML a través de archivos CSS. Estos archivos describen cómo se muestran los diferentes componentes HTML en la pantalla. Por ejemplo, echemos un vistazo a las siguientes clases de estilo del archivo ds4a_styles.css ubicado en la carpetaassets (tenga en cuenta que cada vez que quiera usar un archivo de hojas de estilo en cascada (CSS por sus siglas en inglés) personalizado o importar imágenes, usted tiene que agregarlos a una carpeta llamada assets):
.ds4a-title {
position: fixed;
top: 0;
left: 0;
z-index: 999;
height: 120px;
width: 100%;
margin-left: 16rem;
margin-right: 2rem;
padding: 2rem 1rem;
background-color: #F8F9F9;
}
.ds4a-sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 16rem;
padding: 2rem 1rem;
background-color: #1A5276; /*#EBEDEF;*/
}
Aquí tenemos un par de clases CSS que darán estilo al título y la barra lateral de nuestra aplicación. Puede ver que la barra lateral tiene un ancho 16rem y el título tendrá un margen de16rem - ¡no queremos que ningún otro componente de nuestra aplicación choque con la barra lateral! Además, los hemos configurado para que estén en posición "fija" para que siempre estén visibles.
Por supuesto, definir tus propias clases CSS para cada componente de la aplicación puede ser un poco tedioso. Además, manejar la posición de los componentes a veces puede ser un poco engorroso. Afortunadamente para nosotros, existen varias librerías CSS que podemos usar de forma gratuita. Utilizaremos las librerías Bootstrap CSS y Dash Bootstrap Components, las cuales se pueden agregar a nuestra aplicación de la siguiente manera:
import dash
import dash_bootstrap_components as dbc
app = dash.Dash(__name__, external_stylesheets = [dbc.themes.BOOTSTRAP]) #UTILIZANDO LA LIBRERÍA CSS DE BOOTSTRAP
server = app.server
#Necesitamos esto para funciones callback que no están presentes en la aplicación.
app.config.suppress_callback_exceptions = True
Ahora, ejecutemos el archivo index.py. Debería verse la siguiente aplicación:

Una de las grandes ventajas de la librería Bootstrap es que utiliza un sistema de cuadrícula para diseñar los componentes en la pantalla. Utiliza doce columnas que pueden redimensionarse y reubicarse si lo desea. Usemos el sistema de cuadrícula para centrar el título de nuestro tablero editando el archivo title.py y agregando lo siguiente:
title=html.Div(className="ds4a-title",
children=[
dbc.Row([
dbc.Col(
html.H1("US Sales Dashboard"),
width={"size": 6, "offset": 3}
)
])
],
id="title")
Aquí, hemos creado una sola fila y columna de la cuadrícula. Cambiamos el tamaño de la columna en 6 unidades y la movimos 3 unidades a la derecha.
A continuación, comencemos a llenar nuestra barra lateral. Agregue un componente dcc.DatePickerRange y un componentedcc.Dropdown en la barra lateral. El menú desplegable debe permitir múltiples selecciones de estados en los EE. UU. Use los ID date_picker ystate_dropdown para estos componentes.
Sugerencia: Lea la documentación. Las fechas mínimas y máximas de ventas en nuestro dataset son dt(2014,1,2) y dt(2017,12,31). Para las propiedades value yoptions del menú desplegable, puede cargar el state.json como states y luego usar el código:
options=[{"label":key, "value":states[key]} for key in states.keys()],
value=['CA','NY'],
Es posible que desee agregar algunas palabras en la parte superior de cada componente también.
Respuesta.
A continuación, agreguemos el mapa coroplético de antes en el archivo US_map.py. Luego, agregue el gráfico de línea y el diagrama de dispersión de antes en el archivo stats.py. Estas gráficas deben estar situadas una al lado de la otra. Utilice los identificadores US_map,Line y Scatter.
Pista: Si desea cambiar el color del fondo en cada figura, puede usar lo siguiente:
name_of_figure.update_layout(title='Título de la gráfica',paper_bgcolor="#F8F9F9")
Respuesta.
Ahora es el momento de agregar algo de interactividad a nuestra aplicación! Al final de este ejercicio, nuestra aplicación debería verse así:

Cree una función callback que, tras la selección de fechas, actualice el monto total de ventas en el mapa coroplésico. Agregue esta función después de la definición del diseño en el archivo index.py.
Pista: Puede agregar múltiples entradas a una función callback. Por ejemplo, puede comenzar su llamado con el decorador:
@app.callback(
Output("US_map", "figure"),
[
Input("date_picker", "start_date"),
Input("date_picker", "end_date")
],
)
Respuesta.
Cree una función callback que actualice el diagrama de dispersión y el gráfico de línea de acuerdo con las selecciones de fecha y estado en la barra lateral.
Pista: A partir de la versión Dash 0.39, se permiten múltiples salidas! Puede comenzar su función de la siguiente manera:
@app.callback(
[Output("Line", "figure"),Output("Scatter","figure")],
[
Input("state_dropdown", "value"),
Input("date_picker", "start_date"),
Input("date_picker", "end_date")
],
)
Respuesta.
Nota: ¿Qué sucede si elimina todos los estados del menú desplegable? ¿Qué sucede si selecciona una fecha que no está en el rango del DataFrame? ¡Estos casos deben ser atendidos cuidadosamente! Podemos evitar estos escenarios modificando nuestras funciones callback. Otra posibilidad es utilizar la acción PreventUpdate de la librería dash.exceptions.
Finalmente, permitamos que el usuario agregue estados al menú desplegable haciendo click en el mapa. Esto se puede hacer usando la propiedad clickData de los componentes del gráfico.
Pista: Primero intente crear una función callback que imprima los clickData del gráfico US_map en el terminal. También puede ingresar estados actuales de componentes en una función callback utilizando State ('component_id', 'component_property').
Respuesta.
Ahora tenemos un mapa completamente funcional que se actualiza a medida que cambia el período seleccionado. Intentemos responder las siguientes preguntas de negocio:
Respuesta.
En este caso, creamos un tablero interactivo que permite a los usuarios de la compañía obtener información sobre las ventas y el rendimiento de las ganancias por categoría en diferentes estados. Este tablero nos permitió profundizar en cada estado mediante la selección en un mapa, y facilitó enormemente la comunicación de nuestros hallazgos a una audiencia no técnica.
En este caso, aprendió y creó una aplicación Dash con las siguientes características:
pandas para esos componentesEste tablero se puede implementar en un servidor de AWS o en la intranet privada de una empresa para que lo utilicen todos los interesados.